﻿#include "func_storage.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <string>
#include "transfer_size.h"
//#include "recplan_cfg.h"
#include "record_mp4_blk.h"
#include "VideoRecorder.h"

bool g_bshow_percent = false;
static int g_rec_bit = -1;
static int g_extern_rec = 0 ;
CRecord_mp4_blk g_record_mp4;
string g_record_dir = "/tmp/record";
char  g_dest_disk[64] = "/dev/mmcblk0";
int   g_ch_num = 1;

static void STORAGE_STATUS_CallBackHandle(uint32_t id, const char* param, uint32_t paramLen)
{
    CBAK_REC_STATUS *stRecStatus = NULL;

    fprintf(stderr, "ID[0x%x]\n", id);
    if(id == CALLBACK_ID_FS_RECORD_STATUS)
    {
        stRecStatus = (CBAK_REC_STATUS *)(param);
      //  fprintf(stderr, "ch[%d] recType[%d] diskLeaf[%d MB]\n", stRecStatus->ch, stRecStatus->recType, stRecStatus->diskLeaf);
    }
}


#ifdef  _WIN32
typedef CRITICAL_SECTION     cross_lock_t;
typedef  HANDLE				cross_thread_t;			//线程ID
typedef  LPTHREAD_START_ROUTINE	cross_start_routine;	//线程函数
static void sleep(int secs)
{
    Sleep(secs * 1000);
}
#else
#include <pthread.h>
typedef pthread_mutex_t     cross_lock_t;
typedef  pthread_t		    cross_thread_t;			        //线程ID
typedef  void *(*start_routine)(void*);
typedef  start_routine		cross_start_routine;		//线程函数
#endif


int g_time_zone = 0;
char g_stor_lua[128] = "./stor.lua";
int g_source_type[MAIN_VI_NUMS] = { 0 };

using namespace std;

#define DISK_PATH "/dev/sd"

int print_unix_time( time_t curTm, char *title)
{
    struct tm* timenow;
    timenow = localtime(&curTm);
    fprintf(stderr, "%s %04d-%02d-%02d %2d:%2d:%2d ctime %ld\n",
            title,
            timenow->tm_year+1900, timenow->tm_mon+1, timenow->tm_mday,
            timenow->tm_hour,timenow->tm_min,timenow->tm_sec,curTm);
    return 0;
}


void set_lua_path(char * lua)
{
    strcpy(g_stor_lua,lua);
}

//输入参数：start_routine 线程的执行函数
//			pParam  线程执行时传入的参数
//			pRun    线程是否执行的bool量的指针，如果为NULL，则不理会此参数
//return value: 成功：返回线程ID    *pRun = true
//				失败：返回PUB_CREATE_THREAD_FAIL  *pRun的值不变
cross_thread_t Cross_CreateThread(cross_start_routine start_routine, void* pParam, int *runFlag,int stackSize)
{
    cross_thread_t threadID;
    if (NULL != runFlag)
    {
        *runFlag = 1;
    }
#ifdef _WIN32
    threadID = CreateThread(0, 0, start_routine, (LPVOID)pParam, 0, NULL);
    if ( (NULL == threadID) && (NULL != runFlag) )
    {
        *runFlag = 0;
    }
#elif defined __linux
    int iRet = 0;
    //pthread_t tid;
    pthread_attr_t attr;
    pthread_attr_init( &attr);
    pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED);
    pthread_attr_setstacksize( &attr, stackSize );
    if( (iRet = pthread_create( &threadID, &attr, start_routine, pParam)) != 0 )
    {
        threadID = 0;
        if (NULL != runFlag)
        {
            *runFlag = 0;
        }
    }
    errno = iRet;	//线程创建不会设置错误码，而是直接返回错误码
#endif
    return threadID;
}


int storage_entry(void * arg)
{
    StorageConfig storageCfg;
    int ch = 0;
    time_t cur_tm = 0;
    char local_time[128];
    char gmt_time[128];
    struct tm *timenow = NULL;
    int time_zone = 0;
    int local_hour, utc_hour;
    int data_water = 0;
    unsigned int file_index = 0;
    unsigned int file_sn = 0;
    int file_percent = 0;
    time_t max_rec_tm = 0;
    int ret = 0;
    int  i  = 0;

    uint32_t blk_sz = 32;
    uint32_t part1_sz = 0;
    uint32_t use_sz = 0;

    time(&cur_tm);
    timenow = localtime(&cur_tm);
    local_hour = timenow->tm_hour;
    print_unix_time(cur_tm,"local time");

    timenow = gmtime(&cur_tm);
    utc_hour   = timenow->tm_hour;
    print_unix_time(cur_tm,"utc gmtime");

    //计算出来 时区
    time_zone = local_hour - utc_hour;

    fprintf(stderr,"localtime %s  gmttime %s. utc_tm %d  time_zone %d \n",local_time,gmt_time,(int)cur_tm,time_zone);

    g_time_zone = time_zone;

    memset(&storageCfg,0,sizeof(storageCfg));

    fprintf(stderr,"support SDcord record storageCfg.channelNum %d .\n",g_ch_num );

    //通道数量
    storageCfg.channelNum = g_ch_num;

    storageCfg.bCycleRec  = 1;
    storageCfg.diskNum    = 1;
    storageCfg.bPrepare   = 1;
    storageCfg.bNoneMixAudio = 1;  //不去混合获取音视频数据

    //缓存配置 
    storageCfg.main_media_cache = SIZE_2MB;   //视频缓存
    storageCfg.buf_sz_frame    = SIZE_512KB;  //搬运视频缓存
    storageCfg.buf_sz_replay   = SIZE_1MB + SIZE_256KB; // 回放缓存 
#ifdef _WIN32
    storageCfg.scan_drv_no = 15;
#endif    
    storageCfg.scan_drv_no  = 1;
    storageCfg.manualRecBIT = g_rec_bit; //默认开启所有通道

    storageCfg.buf_sz_flush = SIZE_KB(750); //刷新对齐缓存 
    storageCfg.ch_cfg[0].isEnable = 1;
    storageCfg.ch_cfg[0].stream_type = 0;
    storageCfg.ch_cfg[0].cache_sz = SIZE_2MB;

    STFS_Init(storageCfg);//初始化

    STFS_set_debuglevel(0);
    STFS_RecordModeSet(0,0x01);

    if (-1 == access("/tmp/tfcommon", 0))
    {
        system("mkdir -p /tmp/tfcommon");
    }

    if (-1 == access("/tmp/record", 0))
    {
        system("mkdir -p /tmp/record");
    }

 /*   if (0 == access("/dev/mmcblk0p2", 0))
    {
        system("mount /dev/mmcblk0p2 /tmp/record");
    }*/

    if (0 == access("/dev/mmcblk0p1", 0))
    {
        system("mount /dev/mmcblk0p1 /tmp/record");
    }

    int need_format = 0;
    if (0 == access("/customer/disk_fmt.txt", 0))
    {   //强制格式化磁盘
        need_format = 1;
    }

	if (!STFS_DISK_IS_INIT(g_dest_disk) || need_format)
	{  //未格式化，
		printf("DISK_IS_INIT not init  or need_format %d.\n", need_format);

        if (need_format)
        {
            system("rm  /customer/disk_fmt.txt");
        }
 		ret = STFS_FormatToRecdisk(g_dest_disk, blk_sz, part1_sz, use_sz);
        if (ret == 0)
        { 
            printf("Format disk %s ok.\n", g_dest_disk);
            system("pause");
            system("reboot");
        }
       
        return 0;
	}


	STFS_Buffer_Change(g_source_type, g_ch_num);

    //先使硬盘测试一下，后续会修改成SD卡
    max_rec_tm = STFS_GetRecMaxTime();

    printf("max_rec_tm %d , cur_tm %d .\n",(int)max_rec_tm,(int)cur_tm);
    timenow = localtime(&max_rec_tm);
    local_hour = timenow->tm_hour;
    sprintf(local_time, "record localtime %4d-%02d-%02d %02d:%02d:%02d",  timenow->tm_year+1900,timenow->tm_mon+1,timenow->tm_mday,timenow->tm_hour, timenow->tm_min, timenow->tm_sec);
    printf("storage record time is  %s .\n",local_time);
    
  //  ret = symlink("/tmp/reclist.info", "./www/dbg/reclist");

//    if(max_rec_tm > cur_tm)
//    { 
//#ifndef _WIN32
//        stime(&max_rec_tm); 
//#endif
//    }
    //设置回调函数
    STFS_SET_STATUS_CBAK(STORAGE_STATUS_CallBackHandle);
    //if ( 0== g_extern_rec)
    //{   //内置的录像模块
    //    STFS_RecordSw(1);
    //    ret = STFS_RecordStart();
    //}
    //else
    { 
       //扩展的录像
        g_record_mp4.Init(g_record_dir,"mp4",0,0);
        g_record_mp4.Start(0);
    }

    printf("Storage start record ret %d .\n", ret);

    bool log_record_mp4 = false;
    bool log_get_video = false;
    while(1) 
    {
        sleep(6);
		int isSub = 0;
        //循环查看录像信息
        for (ch = 0; ch < storageCfg.channelNum; ch++)
        {
            data_water =  STFS_FifoGetFrameWater(ch,0);
            file_percent = STFS_GetRecordPercent( ch);
            file_index = STFS_GetRecordIndex(ch);
            file_sn =  STFS_GetRecordSn(ch);

            if(g_bshow_percent && file_percent > 1)
            {
                   printf("ch %02d index %05d file SN %05d percent %d  warter %d \n",
                          ch,file_index,file_sn,file_percent,data_water);
            }
        }
        log_record_mp4 = (access("/tmp/log_record",0)==0 )?  true:false;
        g_record_mp4.show_log(log_record_mp4);
        log_get_video = (access("/tmp/log_video", 0) == 0) ? true : false;
        video_log(log_get_video);
    }

    STFS_RecorcStop();

    printf("storage thread exit.\n");
    return  0;
}

void show_record_percent(int isEnable)
{
    g_bshow_percent = isEnable;
}
void set_record_bit(int sw_bit)
{
    g_rec_bit = sw_bit;
}
void set_extern_rec(int is_extern_rec)
{
    g_extern_rec = is_extern_rec;
}


void set_record_dir(const char* rec_dir)
{
    g_record_dir = rec_dir;
}

int  start_storage(int ch_nums, const char* disk_dev)
{
    //获取参数
    g_ch_num = ch_nums;

    if (disk_dev != NULL && strlen(disk_dev) > 4)
    {
        strcpy(g_dest_disk, disk_dev);
    }
    pthread_t stoage_thread;

    pthread_create(&stoage_thread, NULL, (void* (*)(void*))storage_entry, NULL);
    printf("start storage func.\n");

    return 0;
}